package com.jokerpan.project.config;
import com.jokerpan.project.Handler.*;
import com.jokerpan.project.filter.JWTAuthenticationFilter;
import com.jokerpan.project.filter.JWTAuthorizationFilter;
import com.jokerpan.project.service.impl.UsersServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.lang.annotation.Documented;

/**
 * SpringSecurity配置
 * @author jokerpan
 */
@EnableWebSecurity
//开启权限注解,默认是关闭的
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 未登录
     */
    @Resource
    AuthenticationEnryPoint authenticationEnryPoint;
    /**
     * 登录成功
     */
    @Resource
    AuthenticationSuccess authenticationSuccess;
    /**
     * 登录失败
     */
    @Resource
    AuthenticationFailure authenticationFailure;
    /**
     * 注销成功
     */
    @Resource
    AuthenticationLogout authenticationLogout;
    /**
     * 无权访问
     */
    @Resource
    AccessDeny accessDeny;
    /**
     * 检测异地登录
     */
    @Resource
    SessionInformationExpiredStrategy sessionInformationExpiredStrategy;
    /**
     * 自定义认证逻辑处理
     */
    @Resource
    SelfAuthenticationProvider selfAuthenticationProvider;

    @Bean
    public UserDetailsService userDetailsService() {
        return new UsersServiceImpl();
    }

    /**
     * 加密方式
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 认证
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.authenticationProvider(selfAuthenticationProvider);
        auth.userDetailsService(userDetailsService());
    }

    /**
     * 授权
     */
//    @Override
//    protected void old_configure(HttpSecurity http) throws Exception {
//        //cors()解决跨域问题，csrf()会与restful风格冲突，默认springsecurity是开启的，所以要disable()关闭一下
//        http.cors().and().csrf().disable();
//
//        http.authorizeRequests()
//                //开放注册接口允许所有人访问
//                .antMatchers("/users/register").permitAll()
////                .antMatchers("/oauth/*").permitAll()
//                //hasAuthority 跟数据库权限保持一致【ROLE_ADMIN】而 hasRole则需要数据库中已ROLE开头
////                .antMatchers("/users/*").hasAnyRole("ADMIN", "USER")
////                .antMatchers("/users/queryList").hasRole("USER")
//
//                .and()
//                //开启登录
//                .formLogin()
//                //允许所有人访问
//                .permitAll()
//                // 登录成功逻辑处理
//                .successHandler(authenticationSuccess)
//                // 登录失败逻辑处理
//                .failureHandler(authenticationFailure)
//
//                .and()
//                //开启注销
//                .logout()
//                //允许所有人访问
//                .permitAll()
////                .addLogoutHandler(selfLogoutHandler)
//                //指定是否在注销时让HttpSession无效
//                .invalidateHttpSession(false)
//                //注销逻辑处理
//                .logoutSuccessHandler(authenticationLogout)
//                //删除cookie
//                .deleteCookies("JSESSIONID")
//
//                .and().exceptionHandling()
//                //权限不足的时候的逻辑处理
//                .accessDeniedHandler(accessDeny)
//                //未登录时的逻辑处理
//                .authenticationEntryPoint(authenticationEnryPoint)
//
//                .and()
//                .sessionManagement()
//                //最多只能一个用户登录一个账号
//                .maximumSessions(1)
//                //异地登录的逻辑处理
//                .expiredSessionStrategy(sessionInformationExpiredStrategy);
//    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeRequests()
                .antMatchers("/oauth/login").permitAll()
                .antMatchers("/users/register").permitAll()
                .antMatchers("/users/clearUser").permitAll()
                .antMatchers("/visitors/getIpAddress").permitAll()
                .and()
                //登陆后,访问没有权限处理类
                .exceptionHandling().accessDeniedHandler(accessDeny)
                //匿名访问,没有权限的处理类
                .authenticationEntryPoint(authenticationEnryPoint)
                .and()
                //开启注销
                .logout()
                //允许所有人访问
                .permitAll()
                //指定是否在注销时让HttpSession无效
                .invalidateHttpSession(false)
                //注销成功后逻辑处理
                .logoutSuccessHandler(authenticationLogout)
                //删除cookie
                .deleteCookies("JSESSIONID")
                .and()
                .addFilter(new JWTAuthenticationFilter(authenticationManager())) // 用户登录拦截
                .addFilter(new JWTAuthorizationFilter(authenticationManager()))  // 权限拦截
                // 不需要session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                .and()
                .sessionManagement()
                //最多只能一个用户登录一个账号
                .maximumSessions(1)
                //异地登录的逻辑处理
                .expiredSessionStrategy(sessionInformationExpiredStrategy);
    }


    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

}
